// $Id: XmlImporter.java 18074 2010-07-08 14:45:20Z vsolonenko $
package no.cicero.testframework.common.xml;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.SAXParser;
import java.io.IOException;
import java.io.InputStream;
import java.util.Stack;


public class XmlImporter extends DefaultHandler implements IXmlImporterDelegate{
    
    private SAXParser m_parser = null;
    private Stack<XmlTag> m_tags = null;
    private StringBuffer m_text = null;
    private XmlTag last;
    
    protected String prepareText(XmlTag tag, String text){
        return text;
    }

    private void flushText( XmlTag tag, boolean trim ) throws SAXException{
        String text = ( trim ) ? m_text.toString().trim() : m_text.toString();
        text = prepareText(tag, text);

        if( text.length() != 0 ) {
            tag.getDelegate().handleText( this, tag, text );
        }

        if( m_text.length() != 0 ) {
            m_text.setLength(0);
        }
    }

    public XmlImporter(SAXParser p) {
        m_parser = p;
        m_tags = new Stack<XmlTag>();
        m_text = new StringBuffer();
    }
    
    //----public
    public void doImport(InputStream is) throws SAXException, IOException{
        try{
            m_parser.parse(is, this);
        }finally{
            clearState();
        }
    }
    
    public void pushDelegate(IXmlImporterDelegate delegate) throws SAXException{
        XmlTag tag = m_tags.peek();
        flushText(tag, false );
        tag.setDelegate(delegate);
        delegate.handleStartElement(this, tag);
    }
    
    public void handleStartDocument() throws SAXException {
        //default does nothing
    }
    public void handleEndDocument() throws SAXException {
        //default does nothing
    }

    //----interface org.xml.sax.ContentHandler    
    @Override
    public final void startDocument() throws SAXException {
        m_tags.push(new XmlTag(null, null, null, this));
        handleStartDocument();
    }

    @Override
    public final void endDocument() throws SAXException {
        handleEndDocument();
        m_tags.pop();
    }

    @Override
    public final void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
        XmlTag parent = m_tags.peek();
        flushText( parent, true );
        XmlTag tag = new XmlTag(parent, qName, atts, parent.getDelegate());
        m_tags.push(tag);
        tag.getDelegate().handleStartElement(this, tag);
        last = tag;
    }

    @Override
    public final void endElement(String uri, String localName, String qName) throws SAXException {
        XmlTag tag = m_tags.peek();
        flushText( tag, !last.equals( tag ) );
        tag.getDelegate().handleEndElement(this, tag);
        m_tags.pop();
        if(tag.getDelegate() != m_tags.peek().getDelegate()){
            m_tags.peek().getDelegate().handleEndElement(this, tag);
        }
    }

    @Override
    public final void characters(char[] ch, int start, int length) throws SAXException {
        m_text.append(ch, start, length);
    }

    //----interface org.xml.sax.ErrorHandler
    @Override
    public final void warning(SAXParseException ex) throws SAXException {
        XmlTag tag = m_tags.peek();
        tag.getDelegate().handleWarning(this, tag, ex);
    }

    @Override
    public final void error(SAXParseException ex) throws SAXException {
        XmlTag tag = m_tags.peek();
        tag.getDelegate().handleError(this, tag, ex);
    }

    @Override
    public final void fatalError(SAXParseException ex) throws SAXException {
        XmlTag tag = m_tags.peek();
        tag.getDelegate().handleFatalError(this, tag, ex);
    }

    //----interface IXmlImporterDelegate
    public void handleStartElement(XmlImporter importer, XmlTag tag) throws SAXException {
        //default does nothing
    }
    public void handleEndElement(XmlImporter importer, XmlTag tag) throws SAXException {
        //default does nothing
    }
    public void handleText(XmlImporter importer, XmlTag tag, String text) throws SAXException {
        //default does nothing
    }
    public void handleWarning(XmlImporter importer, XmlTag tag, SAXParseException ex) throws SAXException {
        super.warning(ex);
    }
    public void handleError(XmlImporter importer, XmlTag tag, SAXParseException ex) throws SAXException {
        super.error(ex);
    }
    public void handleFatalError(XmlImporter importer, XmlTag tag, SAXParseException ex) throws SAXException {
        super.fatalError(ex);
    }

    //----private
    private void clearState(){
        m_tags.clear();
    }
}
